package com.kevis.zhunblog.admin.security.config;

import com.kevis.webCommon.constant.UrlConstant;
import com.kevis.webCommon.secure.support.SecureCaptchaSupport;
import com.kevis.zhunblog.admin.handler.SecureAccessDeniedHandler;
import com.kevis.zhunblog.admin.handler.SecureLogoutHandler;
import com.kevis.zhunblog.admin.handler.SecureLogoutSuccessHandler;
import com.kevis.zhunblog.admin.security.service.UserPermissionEvaluator;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

@Configuration
//@EnableWebSecurity  原因就在于我是springboot项目，在非Springboot的Spring Web MVC应用中，该注解@EnableWebSecurity需要开发人员自己引入以启用Web安全。而在基于Springboot的Spring Web MVC应用中,开发人员没有必要再次引用该注解，Springboot的自动配置机制WebSecurityEnablerConfiguration已经引入了该注解。参考： https://blog.csdn.net/qq_39384746/article/details/115865141
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Resource
    private UserDetailsService userDetailsService;

    @Resource
    private SecureCaptchaSupport secureCaptchaSupport;

    @Resource
    private AuthenticationFailureHandler loginFailureHandler;

    @Resource
    private AuthenticationSuccessHandler loginSuccessHandler;

    @Resource
    private SecureLogoutSuccessHandler secureLogoutSuccessHandler;

    @Resource
    private SecureAccessDeniedHandler securityAccessDeniedHandler;

//    @Resource
//    private PersistentTokenRepository securityUserTokenService;

    /******** 下面这些是直接在 SecureExtendConfiguration 中定义了 bean *********/

    @Resource
    private SecureLogoutHandler securityLogoutHandler;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //super.configure(auth);
        //测试用，将加密后的密码直接填入数据库，方便测试
//        String encode = new BCryptPasswordEncoder().encode("123456");
//        System.out.println("encode:"+encode);
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        //这两种过滤都可以。设置下面路径忽略拦截
//        System.out.println(request.getContextPath());
//        System.out.println(request.getServletPath());
//        System.out.println(request.getServletContext().getServletContextName());
        //参考： https://blog.csdn.net/liuminglei1987/article/details/106896276
        //web.ignoring().mvcMatchers("/static/**", "/common/**", "/plugins/**", "/themes/**", "/*/favicon.ico").servletPath("/hm/admin");
        web.ignoring().antMatchers( "/common/**", "/plugins/**", "/themes/**", "/favicon.ico","/resources/**");
        //web.ignoring().antMatchers("/hm/admin/common/**", "/hm/admin/plugins/**", "/hm/admin/themes/**", "/*/favicon.ico");
        //web.ignoring().antMatchers("/**/*.css", "/**/*.js", "/**/*.jpg", "/**/*.png", "/**/*.gif", "/**/*.map", "/**/*.html","/*.ico", "/**/*.ico", "/**/*.svg", "/**/*.woff", "/**/*.ttf");
        super.configure(web);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http);
//        http.logout().logoutUrl("/hm/admin/loginOut")
//                //.logoutSuccessUrl("/test/hello");
//                .logoutSuccessUrl("/hm/admin/login");

        http.addFilterBefore(secureCaptchaSupport, UsernamePasswordAuthenticationFilter.class);//添加验证码校验过滤器

        //配置没有权限访问自定义跳转的页面
        //https://blog.csdn.net/abcwanglinyong/article/details/80881391
        //https://blog.csdn.net/jkjkjkll/article/details/79975975
        http.exceptionHandling().accessDeniedPage("/unauth.html");

        http.formLogin()//自定义自己编写的登陆页面
                .loginPage(UrlConstant.ADMIN_LOGIN_URL)//登录页面
                .loginProcessingUrl(UrlConstant.ADMIN_LOGINP_ROCESSING_URL)//登录访问路径,随意写,页面登录地址需要与这个一致
                /**
                 * 登录成功
                 */
                .successHandler(loginSuccessHandler)
                //.successForwardUrl("/hm/admin/index")//要跳转到post的方法才生效
                //.defaultSuccessUrl("/hm/admin/index")//登录成功之后，跳转路径,如果有上一页,则会跳转之前页面，否则为这个地址
                /**
                 * 登录失败
                 */
                .failureHandler(loginFailureHandler)
                //.failureUrl("/hhm/login")//这种方式是跳转
                //.failureHandler(new LoginFailureHandler("/hhm/login"))
                //.failureForwardUrl("/hhm/login")//要跳转到post的方法才生效
                /**
                 * 登出
                 */
                .and().logout()
                .addLogoutHandler(securityLogoutHandler)
                //.logoutUrl("/logOut")
                .logoutSuccessHandler(secureLogoutSuccessHandler)
                //.logoutSuccessUrl("/login")
                // 退出登录删除 cookie缓存
                .deleteCookies("JSESSIONID")

                .and().authorizeRequests()//设置开启权限验证
                .antMatchers("/login", "/loginProcessing", "/logOut", "/test/test1", "/test/test2", "/code/image","/resources/**").permitAll()//给指定的地址授权,也就是这些地址有了权限,跳过验证了
                //静态资源相关的，也可以在这里进行设置进行授权不拦截
                //.antMatchers("/**/*.css", "/**/*.js", "/**/*.jpg", "/**/*.png", "/**/*.gif", "/**/*.map", "/**/*.html", "/**/*.ico", "/**/*.svg").permitAll()
                //.mvcMatchers("/favicon.ico").servletPath("/hm/admin").permitAll()

                .anyRequest().authenticated()//访问任何资源都需要身份认证，也就是需要登录
                //配置没有权限访问自定义跳转的页面
                //.and().exceptionHandling().accessDeniedPage("/unauth.html")
                .and().exceptionHandling().accessDeniedHandler(securityAccessDeniedHandler)
                /**
                 * 记住我的功能
                 */
                .and().rememberMe()
                .rememberMeParameter("remember-me") //页面的记住我的name一致
                .rememberMeCookieName("rememberme-token") // cookie的名称
                .key("kevis")//key() 方法的参数是一个字符串类型的值，表示用于加密记住我 cookie 的密钥
                //.tokenRepository(securityUserTokenService)//暂时用默认的，只要 bean创建一个就好
                .tokenValiditySeconds(604800)//设置有效时长，单位秒
                .and().headers().frameOptions().disable()// 解决这个问题： chrome-error://chromewebdata/:1 Refused to display 'http://localhost:13152/' in a frame because it set 'X-Frame-Options' to 'deny'.

                .and().csrf().disable()//项目初期为了方便测试,先不要csrf，后期需要去掉,启动csrf，保证安全
        ;
    }
}
